<template>
    <div class="block" :style="blockStyle" ref="blockRef" @click.stop="onClickBlock()">
        <div class="title">{{ data.block_name }}</div>
        <div class="content">
            <ul class="entries">
                <li v-for="(entry, index) in filteredEntries" :key="index">
                    <div class="entry-row" :class="`${entry.entry_value.block_name ? 'block' : 'layer'}`" @click.stop="toggleExpand(index)">
                        <div class="entry-name">{{ entry.entry_value.block_name ? `${entry.entry_value.block_name} (${entryCount(entry)})` : entry.entry_value.layer_name }}</div>
                        <el-icon v-if="!isExpanded[index]">
                            <CirclePlus class="expand-icon" />
                        </el-icon>
                        <el-icon v-if="isExpanded[index]">
                            <Remove class="expand-icon" />
                        </el-icon>
                    </div>
                </li>
            </ul>
        </div>
        <svg :width="svgWidth" :height="svgHeight" class="connections">
            <path
                v-for="(entry, index) in filteredEntries"
                :key="'path-' + index"
                :d="isExpanded[index] ? calculatePath(index) : ''"
                stroke="black"
                fill="transparent"
                stroke-width="2"
                marker-end="url(#arrowhead)"
            />
        </svg>
    </div>
    <div v-for="(entry, index) in filteredEntries" :key="index">
        <div v-if="isExpanded[index]">
            <entry
                v-if="entry.entry_value"
                :data="entry.entry_value"
                :position="entryPosition(index)"
                :layer="layer"
                :ref="`childRef_${index}`"
                :index="index"
                @update-position="updatePosition"
            />
        </div>
    </div>
</template>

<script setup>
import { CirclePlus } from '@element-plus/icons-vue';
import Entry from './Entry.vue';
import { computed, ref, onMounted, nextTick, getCurrentInstance } from 'vue';
const { proxy } = getCurrentInstance();
const props = defineProps({
    data: Object,
    position: {
        type: Object,
        required: true
    },
    layer: {
        type: Number,
        required: true
    },
    index: {
        type: Number,
        required: true
    }
});
const emit = defineEmits(['toggleExpand', 'updatePosition']);

const svgWidth = 300;
const svgHeight = 500;
const blockRef = ref(null);
const entryRefs = ref([]);
const isExpanded = ref([]);
const entryPosY = ref([]);
const blockStyle = computed(() => ({
    position: 'absolute',
    left: `${props.position.x}px`,
    top: `${props.position.y}px`,
    minWidth: '250px',
    padding: '10px',
    border: '1px solid #ddd',
    backgroundColor: '#f9f9f9',
    boxShadow: '2px 2px 5px rgba(0, 0, 0, 0.1)',
    display: 'inline-block'
}));

const filteredEntries = computed(() => props.data.block_entries.filter((entry) => entry.entry_name !== 'init_cfg'));
const entryPosition = computed(() => {
    return (index) => {
        let pos = null;
        if (entryPosY.value[index]) {
            pos = { x: props.position.x + 350, y: props.position.y + entryPosY.value[index] };
        } else {
            pos = { x: props.position.x + 350, y: props.position.y };
        }
        // console.log(`index = ${index}, position = `, pos);
        return pos;
    };
});

const entryCount = computed(() => {
    return (entry) => {
        if (entry.entry_value.block_name) {
            return entry.entry_value.block_entries.length;
        } else {
            return 0;
        }
    };
});
function onClickBlock() {
    const blockRect = getBlockRect();
    console.log(`layer = ${props.layer}\nposition = `, props.position, `\nblockRect = `, blockRect);
}

// 获取block嵌套所有内容的外接矩形
function getBlockRect() {
    const blockRect = blockRef.value.getBoundingClientRect();
    let right = blockRect.right;
    let bottom = blockRect.bottom;
    for (let i = 0; i < filteredEntries.value.length; i++) {
        let refIndex = `childRef_${i}`;
        if (proxy.$refs[refIndex]) {
            let childRef = proxy.$refs[refIndex][0];
            if (childRef) {
                let childRect = childRef.getBlockRect();
                if (childRect.right > right) {
                    right = childRect.right;
                }
                if (childRect.bottom > bottom) {
                    bottom = childRect.bottom;
                }
            }
        }
    }
    const compRect = {
        left: blockRect.left,
        top: blockRect.top,
        right: right,
        bottom: bottom,
        width: right - blockRect.left,
        height: bottom - blockRect.top
    };
    return compRect;
}

async function toggleExpand(index) {
    // console.log(`=> ${props.data.block_name} ${index}`);

    // 更新对应子元素的状态
    isExpanded.value[index] = !isExpanded.value[index];
    await nextTick();

    // 更新所有entry的y坐标位置
    let gap = 20;
    let endY = -gap;
    for (let i = 0; i < isExpanded.value.length; i++) {
        let expanded = isExpanded.value[i];
        if (expanded) {
            entryPosY.value[i] = endY + gap;

            let refIndex = `childRef_${i}`;
            if (proxy.$refs[refIndex]) {
                let childRef = proxy.$refs[refIndex][0];
                if (childRef) {
                    let childHeight = childRef.getBlockRect().height;
                    endY += childHeight + gap;
                }
                // console.log(`layer = ${props.layer}, index = ${i}, endY = ${endY}`, proxy.$refs[refIndex]);
            }
        } else {
            entryPosY.value[i] = null;
        }
    }

    // 如果是展开某个元素，则告知上一层，同步更新位置
    await nextTick();
    emit('toggleExpand', index);
}

function updatePosition(index) {
    // console.log(`## ${props.data.block_name} @${index}`);

    // 递归更新兄弟节点
    let gap = 20;
    let endY = -gap;
    for (let i = 0; i < filteredEntries.value.length; i++) {
        // 重新计算block的位置
        let refIndex = `childRef_${i}`;
        if (isExpanded.value[i]) {
            entryPosY.value[i] = endY + gap;
            if (proxy.$refs[refIndex]) {
                let childRef = proxy.$refs[refIndex][0];
                if (childRef) {
                    let childHeight = childRef.getBlockRect().height;
                    endY += childHeight + gap;
                }
            }
        } else {
            entryPosY.value[i] = null;
        }
    }

    // 更新上一层父亲节点
    emit('updatePosition', props.index);
}

function calculatePath(index) {
    const entryElement = entryRefs.value[index];
    if (!entryElement) return '';

    const entryRect = entryElement.getBoundingClientRect();
    const blockRect = blockRef.value.getBoundingClientRect();

    const startX = entryRect.right - blockRect.left;
    const startY = entryRect.top + entryRect.height / 2 - blockRect.top;
    const endX = startX + 105;
    // const endY = index * 100 + 30;
    const endY = props.position.y + entryPosY.value[index] - props.position.y + 30;

    return `M ${startX} ${startY} C ${startX + 50} ${startY} ${endX - 50} ${endY} ${endX} ${endY}`;
}

onMounted(() => {
    nextTick(() => {
        entryRefs.value = blockRef.value.querySelectorAll('li');
        isExpanded.value = Array(filteredEntries.value.length).fill(false);
        entryPosY.value = Array(filteredEntries.value.length).fill(null);
    });
});

defineExpose({ getBlockRect });
</script>

<style scoped>
.title {
    background-color: #e0e0e0;
    padding: 10px;
    font-weight: bold;
    text-align: center;
}

.content {
    background-color: #fff;
    padding: 10px;
    margin-top: 10px;
}

.entries {
    list-style: none;
    padding: 0;
    margin: 0;
    position: relative;
}

.entry-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 5px;
    cursor: pointer;
    padding: 5px 10px;
    user-select: none;
}

.entry-row:hover {
    background-color: #f0f0f0;
}

.entry-row.layer {
    color: rgb(202, 156, 7);
    font-weight: 500;
}

.expand-icon {
    color: black;
    cursor: pointer;
}

.connections {
    position: absolute;
    top: 0;
    left: 0;
    overflow: visible;
    pointer-events: none;
    z-index: 1;
}

.entry-name {
    font-size: 14px;
}
</style>
